home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / WINER.ZIP / SORT.ASM < prev    next >
Assembly Source File  |  1992-05-13  |  7KB  |  204 lines

  1. ;********** SORT.ASM - sorts an entire BASIC string array
  2. ;
  3. ;Copyright (c) 1991 Ethan Winer
  4. ;
  5. ;
  6. ;Usage:
  7. ;
  8. ;   CALL Sort(Array$(), Direction)
  9. ;
  10. ;Where Array$() is the array to sort, and Direction is 0 for ascending
  11. ;(normal sort), or anything else for descending (backwards sort).
  12.  
  13. .Model Medium, Basic
  14. .Data
  15.     S          DW 0
  16.     F          DW 0
  17.     L          DW 0
  18.     I          DW 0
  19.     J          DW 0
  20.     MidPoint   DW 0
  21.  
  22. .Code
  23.     Extrn B$SWSD:Proc   ;this swaps two strings
  24.     Extrn B$SCMP:Proc   ;this compares two strings
  25.  
  26. Sort Proc Uses SI DI ES, Array:Word, Dir:Word
  27.  
  28.     Cld                 ;all fills and compares are forward
  29.     Push DS             ;ensure that ES = DS for string compares below
  30.     Pop  ES
  31.     
  32.     Xor  CX,CX          ;clear CX for comparing and assigning below
  33.     Mov  AX,7376h       ;load AL and AH with the opcodes for "Jae" and "Jbe"
  34.                         ;  in preparation for code self-modification
  35.     Mov  BX,Dir         ;get the sorting direction
  36.     Cmp  [BX],CX        ;is it zero meaning an ascending sort? (CX is now 0)
  37.     Je   Ascending      ;yes, skip ahead
  38.     Xchg AL,AH          ;no exchange the "Jbe" and "Jae" opcodes
  39.  
  40. Ascending:
  41.     Mov  CS:[X1],AH     ;install the correct comparison opcodes based on
  42.     Mov  CS:[X2],AL     ;  the sort direction
  43.  
  44.     Mov  SI,Array       ;load the base address of the array descriptor
  45.     Mov  AX,[SI+0Eh]    ;now AX holds the number of elements in the array
  46.     Dec  AX             ;adjust the number of elements to zero-based
  47.     Jns  L0             ;at least 1 element was specified, continue
  48.     Jmp  L4             ;we can't sort 0 (or less!) elements, get out now!
  49.  
  50. L0:
  51.     Push AX                 ;save the number of elements while we multiply
  52.     Mov  BX,[SI+0Ah]        ;now BX holds the adjusted offset value
  53.     Mov  AX,4               ;each element is four bytes long
  54.     Mul  Word Ptr [SI+10h]  ;multiply that by the first element number
  55.     Add  BX,AX              ;now BX holds the address of the first element
  56.     Pop  AX                 ;retrieve the number of elements
  57.     
  58.     Mov  S,SP           ;S = 0 (really normalized to current stack pointer)
  59.     Mov  F,CX           ;F = 0
  60.     Mov  L,AX           ;L = Size%
  61.  
  62.     ;----- calculate MidPoint
  63. L1:
  64.     Mov  DI,L           ;MidPoint = (L + F) \ 2
  65.     Add  DI,F
  66.     Shr  DI,1
  67.     Mov  MidPoint,DI
  68.  
  69.     Mov  AX,F           ;I = F
  70.     Mov  I,AX
  71.  
  72.     Mov  AX,L           ;J = L
  73.     Mov  J,AX
  74.  
  75.     ;----- calculate offset into the descriptor table for Array$(MidPoint)
  76. L1_2:
  77.  
  78.     Shl  DI,1           ;multiply MidPoint in DI times 4
  79.                         ;  (4 bytes per descriptor) by shifting twice
  80.     Shl  DI,1           ;now DI holds how far beyond Array$(Start)
  81.                         ;  Array$(MidPoint)'s descriptor is
  82.     Add  DI,BX          ;add the array base address to produce the final
  83.                         ;  descriptor address for Array$(MidPoint)
  84.  
  85.     ;----- calculate descriptor offset for Array$(I)
  86. L2:
  87.     Mov  SI,I           ;put I into SI
  88.     Shl  SI,1           ;as above
  89.     Shl  SI,1           ;now SI holds how far beyond Array$(Start)
  90.                         ;  Array$(I)'s descriptor is
  91.     Add  SI,BX          ;add base to produce the final descriptor address
  92.  
  93.     ;IF Array$(I) < Array$(MidPoint) THEN I = I + 1: GOTO L2
  94.     Push BX             ;save BX because B$SCMP trashes it
  95.     Push SI
  96.     Push DI
  97.     Call B$SCMP         ;do the compare
  98.     Pop  BX             ;restore BX
  99.  
  100. X1 Label Byte           ;modify the code below to "Jbe" if descending sort
  101.     Jae  L2_1           ;Array$(I) isn't less, continue on
  102.  
  103.     Inc  Word Ptr I     ;I = I + 1
  104.     Jmp  Short L2       ;GOTO L2
  105.  
  106.     ;----- calculate descriptor offset for Array$(J)
  107. L2_1:
  108.     Mov  SI,J           ;put J into SI
  109.     Shl  SI,1           ;as above
  110.     Shl  SI,1           ;now SI holds how far beyond Array$(Start)
  111.                         ;  Array$(J)'s descriptor is
  112.     Add  SI,BX          ;add base to produce the final descriptor address
  113.  
  114.     ;IF Array$(J) > Array$(MidPoint) THEN J = J - 1: GOTO L2.1
  115.     Push BX             ;preserve BX
  116.     Push SI
  117.     Push DI
  118.     Call B$SCMP         ;do the compare
  119.     Pop  BX             ;restore BX
  120.  
  121. X2 Label Byte           ;modify the code below to "Jae" if descending sort
  122.     Jbe  L2_2           ;Array$(J) isn't greater, continue on
  123.  
  124.     Dec  Word Ptr J     ;J = J - 1
  125.     Jmp  Short L2_1     ;GOTO L2.1
  126.  
  127. L2_2:
  128.     Mov  AX,I           ;IF I > J GOTO L3
  129.     Cmp  AX,J
  130.     Jg   L3             ;J is greater, go directly to L3
  131.     Je   L2_3           ;they're the same, just skip the swap
  132.  
  133.     ;Swap Array$(I), Array$(J) - must also reassign MidPoint to
  134.     ;                            follow the changes in I and J
  135.  
  136.     Mov  SI,I           ;put I into SI
  137.     Mov  DI,J           ;put J into DI
  138.  
  139.     Cmp  SI,MidPoint    ;IF I = MidPoint THEN MidPoint = J
  140.     Jne  No_Mid1        ;not equal, skip ahead
  141.     Mov  MidPoint,DI    ;equal, assign MidPoint = J
  142.     Jmp  Short No_Mid2  ;don't waste time comparing again
  143.  
  144. No_Mid1:
  145.     Cmp  DI,MidPoint    ;IF J = MidPoint THEN MidPoint = I
  146.     Jne  No_Mid2        ;not equal, skip ahead
  147.     Mov  MidPoint,SI    ;equal, assign MidPoint = I
  148.  
  149. No_Mid2:
  150.     Mov  SI,I           ;put I into SI
  151.     Shl  SI,1           ;multiply times four for the descriptors
  152.     Shl  SI,1
  153.     Add  SI,BX          ;add the address for the first descriptor
  154.  
  155.     Mov  DI,J           ;do the same for J in DI
  156.     Shl  DI,1
  157.     Shl  DI,1
  158.     Add  DI,BX
  159.  
  160.     Push BX             ;save BX in case B$SWSD destroys it
  161.     Call B$SWSD         ;and swap 'em good
  162.     Pop  BX
  163.  
  164. L2_3:
  165.     Inc  Word Ptr I     ;I = I + 1
  166.     Dec  Word Ptr J     ;J = J - 1
  167.  
  168.     Mov  AX,I           ;IF I <= J GOTO L2
  169.     Cmp  AX,J
  170.     Jg   L3             ;it's greater, skip to L3
  171.     Mov  DI,MidPoint    ;get MidPoint again
  172.     Jmp  L1_2           ;go back to just before L2
  173.  
  174. L3:
  175.     Mov  AX,I           ;IF I < L THEN PUSH I: PUSH L
  176.     Cmp  AX,L
  177.     Jnl  L3_1           ;it's not less, so skip Pushes
  178.  
  179.     Push I              ;Push I
  180.     Push L              ;Push L
  181.  
  182. L3_1:
  183.     Mov  AX,J           ;L = J
  184.     Mov  L,AX
  185.  
  186.     Mov  AX,F           ;IF F < L GOTO L1
  187.     Cmp  AX,L
  188.     Jnl  L3_2           ;it's not less, so jump ahead to L3_2
  189.     Jmp  L1             ;it's less, go to L1
  190.  
  191. L3_2:
  192.     Cmp  S,SP           ;IF S = 0 GOTO L4
  193.     Je   L4
  194.  
  195.     Pop  L              ;Pop L
  196.     Pop  F              ;Pop F
  197.     Jmp  L1             ;GOTO L1
  198.  
  199. L4:
  200.     Ret                 ;return to BASIC
  201.  
  202. Sort Endp
  203. End
  204.